package uqbar.aspectj.observable.mixin;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

import uqbar.aspectj.utils.Utils;

/**
 * @author uqbar
 */
public aspect ObservableByMixinAspect {

	declare parents : @Observable * implements ObservableObjectSupport;

	pointcut fieldWrite(ObservableObjectSupport target, Object newValue) : 
		set(* *..*)
		&& args(newValue) 
		&& target(@Observable target)
		&& !withincode(*.new(..))
		&& within(@Observable *);

	void around(ObservableObjectSupport target, Object newValue) : fieldWrite(target, newValue) {
		String fieldName = thisJoinPoint.getSignature().getName();
		Object oldValue = Utils.getField(target, fieldName);

		proceed(target, newValue);

		// comparar por null y por equals ?
		if (oldValue != newValue) {
			target.fieldChanged(fieldName, oldValue, newValue);
		}
	}

	after(ObservableObjectSupport target) : initialization(* ..*.new(..) ) && target(target) {
		target.initialize();
	}
	
	// ***********************************************************
	// ** Added members
	// ***********************************************************
	
	private transient PropertyChangeSupport ObservableObject.changeSupport;
	
	public void ObservableObject.initialize() {
		this.changeSupport = new PropertyChangeSupport(this);
	}
	
	public void ObservableObject.addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
		this.changeSupport.addPropertyChangeListener(propertyName, listener);
	}
	
	public void ObservableObject.removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
		this.changeSupport.removePropertyChangeListener(propertyName, listener);
	}
		
	public void ObservableObject.fieldChanged(String fieldName, Object oldValue, Object newValue) {
		this.changeSupport.firePropertyChange(fieldName, oldValue, newValue);
	}
	
}
